package org.acghub.common.reload;

import lombok.Getter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class ReloadCfgWrapper {

    @Getter
    private final String cfgClassName;

    @Getter
    private Class<?> clazz;
    @Getter
    private Throwable cause;
    private Method reloadXml;
    private Method setAll;
    private Method resetOldAll;
    private Field all;

    private Map<?, ?> newAll;
    private Map<?, ?> oldAll;

    // private MethodHandle reloadXml_MH;
    // private MethodHandle setAll_MH;
    // private MethodHandle resetOldAll_MH;

    public ReloadCfgWrapper(String cfgClassName) {
        this.cfgClassName = cfgClassName;
    }

    /**
     * �׶�1 ������ͷ���
     *
     * @return
     */
    public boolean parse() {
        try {
            this.clazz = Class.forName(cfgClassName);

            this.reloadXml = this.clazz.getDeclaredMethod("reloadXml", String.class, Map.class);
            this.setAll = this.clazz.getDeclaredMethod("setAll", Map.class);
            this.resetOldAll = this.clazz.getDeclaredMethod("resetOldAll");

            this.all = this.clazz.getDeclaredField("all");
            this.all.setAccessible(true);
        } catch (Exception e) {
            this.cause = e;
            return false;
        }
        return true;

    }


    public boolean reload(String cfgDir) {
        try {
            this.newAll = new HashMap<>();
            this.reloadXml.invoke(null, cfgDir, newAll);
        } catch (Exception e) {
            this.cause = e;
            return false;
        }
        return true;
    }


    public boolean update() {
        try {
            this.oldAll = (Map<?, ?>) this.all.get(null);

            this.setAll.invoke(null, newAll);
            this.resetOldAll.invoke(null);
        } catch (Exception e) {
            this.cause = e;
            return false;
        }
        return true;

    }

    public void recover() {
        try {
            if (this.oldAll != null) {
                this.all.set(null, oldAll);
            }
        } catch (Exception e) {
            this.cause = e;
        }
    }


    public void close() {
        // help GC
        this.clazz = null;
        this.cause = null;
        this.reloadXml = null;
        this.setAll = null;
        this.resetOldAll = null;
        this.newAll = null;
        this.oldAll = null;
    }

}
